{*******************************************************}
{*
{* oWorldManager.pas
{* Created on:      24-II-2010
{* Original author: Miroslav Rusin
{*
{*******************************************************}

{ varga
chyba typecastu alebo coho pri:
PO_GET_PHYSICAL_ENTITIES_FOR_PEDESTRIAN
PO_INSERT_PEDESTRIAN
PO_MOVE_PEDESTRIAN
PO_DELETE_PEDESTRIAN
}

unit oSceneManager;

interface

uses Vector, Classes, oLevel, oCoordinates, oPedestrian, oLogicalEntity,oPhysicalEntity,
  oManager, oEntity, oScene, Generics.Collections, oProcessObjectConstants, oProcessItem,
  SysUtils, oPolygon, oProcessObjects, obstacle, oWaypoint, oEntityTypeConstants;

type

  ESceneManager = class(Exception)

  end;

  TSceneManager = class (TManager)
  private
    aScene : TScene;
    aPath : string;
    aPhysLayer : string;
    aLayerIndex, aEntityId : integer;
    function createPhysicalEntity(paType : integer; paPoints : TProcessingObject) : TPhysicalEntity;
  public
//    function ProcessObject(paMap: TProcessList): TProcessList; override;
    function ProcessObject(paItem: TProcessItem): TProcessItem; override;
    constructor Create; overload;
    constructor Create(paMaster : TManager); overload;
    destructor Destroy; override;
    property Scene : TScene read aScene write aScene;

    property EntityId : integer read aEntityId write aEntityId;

    procedure test;
  end;

implementation



{implementation of TWorldManager}

constructor TSceneManager.Create;
var
  level : TLevel;
begin
  aScene := TScene.Create;
  aLayerIndex := 0;
  aEntityId := 0;
end;

constructor TSceneManager.Create(paMaster: TManager);
begin
  Create;
  aMaster := paMaster;
end;

function TSceneManager.createPhysicalEntity(paType: integer; paPoints : TProcessingObject): TPhysicalEntity;
var
  phys : TPhysicalEntity;
  pointlist : TPointsList;
  points : TList;
  j : integer;
  point : TVector;
begin
  phys := nil;
    case paType of
      ET_POLYGON : begin
        pointlist := TProcessingPointsList(paPoints).List;
        points := TList.Create;
        for j := 0 to pointlist.Count - 1 do
          begin
            point := pointlist[j];
            points.Add(TCoordinates.Create(point.X, point.Y));
          end;
        phys := TPolygon.Create(points, EntityId);
      end;
    end;
  result := phys;
end;

destructor TSceneManager.Destroy;
begin
  inherited Destroy;
end;

function TSceneManager.ProcessObject(
  paItem: TProcessItem) : TProcessItem;
var
  listE : Tlist<TEntity>;
  inList, outList : TProcessingList;
  procphys : TProcessingPhysEntity;
  e : Tentity;
  e1 : TEntityProcessing;
  name, path, newname : Tstring;
  phys : TPhysicalEntity;
  log : TLogicalEntity;
  waypoint : TWaypoint;
  value, id : TInteger;
  height, width : Treal;
  entity: TEntity;
  res : boolean;
  item : TProcessItem;
  j : integer;
  level : TLevel;
begin

  inList := nil;
  outList := nil;
  name := nil;
  value := nil;

  if paItem.Data <> nil then
  if paItem.Data is TProcessingList then
      inList := TProcessingList(paItem.Data)
    else
        if paItem.Data is TString then
          name := TString(paItem.Data)
        else
          if paItem.Data is TInteger then
            value := TInteger(paItem.Data)
          else
             if paItem.Data is TProcessingPhysEntity then
                procphys := TProcessingPhysEntity(paItem.Data)
             else
             raise ESceneManager.Create('WorldManger: Expected TProcessingList or TString'
             +' or TProcessingXML instance, got ' +
              paItem.ClassName);


  case (paItem.Code) of
    PO_SCENE_INSERT_PHYSICAL_ENTITY :
       begin
         try
          value := TInteger(inList.Parameters[1]);
          phys := createPhysicalEntity(value.Integer_, inList.Parameters[0]);

          if Scene.addPhysicalEntity(aLayerIndex,
           phys,
           EntityId) then
            begin
              inc(aEntityId);
              Result := TProcessItem.create(PO_SUCCESS, TInteger.Create(aEntityId - 1));
            end
          else
            Result := TProcessItem.create(PO_FAILURE, NIL);
        except
          on e : Exception do raise ESceneManager.Create('Error on insert');
          on es : ESceneManager do Result := TProcessItem.create(PO_FAILURE, nil);
        end;
       end;
    PO_SCENE_GET_ALL_PEDESTRIANS : begin
        Result := TProcessItem.create(PO_EDITOR_GET_PEDESTRIANS,
                TProcessingPedestrianList.Create(
                scene.getLevel(aLayerIndex).AllPedestrians));
    end;
    PO_SCENE_MOVE_LOGICAL_ENTITY : begin
      value := TInteger(inList.Parameters[1]);
      phys := createPhysicalEntity(value.Integer_, inList.Parameters[0]);
      id := TInteger(inList.Parameters[2]);
      scene.Levels[aLayerIndex].moveLogicalEntity(id.Integer_, phys);
      inlist.addParameter(TProcessingPointsList.Create(TPointsList(nil)));
    end;

    PO_SCENE_INSERT_LOGICAL_ENTITY : begin
      try
        value := TInteger(inList.Parameters[0]);
        phys := createPhysicalEntity(ET_POLYGON, inList.Parameters[1]);

        if Scene.getLevel(aLayerIndex).insertLogicalEntity(EntityId,
        value.Integer_, phys, aLayerIndex) <> nil then
         begin
           inc(aEntityId);
           Result := TProcessItem.create(PO_SUCCESS, TInteger.Create(aEntityId - 1));
         end
        else
         Result := TProcessItem.create(PO_FAILURE, nil);
      except
         on e : Exception do raise ESceneManager.Create('Error on insert log. entity');
         on e : ESceneManager do Result := TProcessItem.create(PO_FAILURE, nil);
      end;
    end;

    PO_SCENE_INSERT_LOGICAL_ENTITY_TO_PHYS_ENTITY :
       begin
        try
          res := Scene.getLevel(aLayerIndex).InsertLogicalEntity(
          TInteger(inList.Parameters[0]).Integer_,
          TInteger(inList.Parameters[1]).Integer_, aLayerIndex);
          if res then
            Result := TProcessItem.create(PO_SUCCESS, NIL)
          else
            Result := TProcessItem.create(PO_FAILURE, NIL)
        except
          on e : Exception do raise ESceneManager.Create('Error on insert');
          on es : ESceneManager do Result := TProcessItem.create(PO_FAILURE, nil);
        end;
       end;

    PO_SCENE_DELETE_PHYSICAL_ENTITY :
       begin
        try
          res := Scene.getLevel(aLayerIndex).deletePhysicalEntity(
          value.Integer_);
          if res then
            Result := TProcessItem.create(PO_SUCCESS, NIL)
          else
            Result := TProcessItem.create(PO_FAILURE, NIL)
        except
          on e : Exception do raise ESceneManager.Create('Error on delete');
          on es : ESceneManager do Result := TProcessItem.create(PO_FAILURE, nil);
        end;
       end;

    PO_SCENE_MOVE_PHYSICAL_ENTITY :
       begin
          value := TInteger(inList.Parameters[1]);
          phys := createPhysicalEntity(value.Integer_, inList.Parameters[0]);

          res := Scene.getLevel(aLayerIndex).movePhysicalEntity(
          TInteger(inList.Parameters[2]).Integer_,
          phys);
          if res then
            Result := TProcessItem.create(PO_SUCCESS, NIL)
          else
            Result := TProcessItem.create(PO_FAILURE, NIL)
       end;

    PO_SCENE_DELETE_LOGICAL_ENTITY :
       begin
        try
          res := Scene.getLevel(aLayerIndex).DeleteLogicalEntity(
          value.Integer_);
          if res then
            Result := TProcessItem.create(PO_SUCCESS, NIL)
          else
            Result := TProcessItem.create(PO_FAILURE, NIL)
        except
          on e : Exception do raise ESceneManager.Create('Error on insert');
          on es : ESceneManager do Result := TProcessItem.create(PO_FAILURE, nil);
        end;
       end;

    PO_SCENE_GET_PHYSICAL_ENTITY :
       begin
          phys := Scene.getPhysicalEntityById(value.Integer_);
          if phys <> nil then
            Result := TProcessItem.create(PO_SUCCESS,
            TProcessingPhysEntity.Create(phys))
          else
            Result := TProcessItem.create(PO_FAILURE, NIL);
       end;

    PO_SCENE_GET_LOGICAL_ENTITY :
       begin
          e := Scene.getEntityById(value.Integer_);
        if e <> nil then
          Result := TProcessItem.create(PO_SUCCESS, TEntityProcessing.Create(e))
        else
          Result := TProcessItem.create(PO_FAILURE, nil)
       end;

    PO_SCENE_SAVE :
      begin
        if TString(inList.Parameters[0]).String_ <> '' then
         begin
           Scene.SaveToXML(TString(inList.Parameters[0]).String_,
            TProcessingMap(inList.Parameters[1]).Map,
            TProcessingMap(inList.Parameters[2]).Map
           );
           Result := TProcessItem.create(PO_SUCCESS, NIL);
         end
        else
          Result := TProcessItem.create(PO_FAILURE, NIL);
      end;

    PO_SCENE_SAVE_ACTUAL_LAYER : begin
      value := inList.Parameters[0];
      path := inList.Parameters[1];
      level := Scene.Levels[0];
      if level <> nil then begin
        if value.Integer_ = PHYS_LAYER then
          level.SavePhysToXML(aPath + '\phys_layers\' + path.String_ + '.xml')
        else
          level.SaveLogToXML(aPath + '\log_layers\' + path.String_ + '.xml');
//        Scene.Levels.Delete(scene.getLevelIndex(name.String_, value.Integer_));
       end
    end;

    PO_SCENE_SAVE_LAYER : begin
      name := TString(inList.Parameters[0]);
      path := TString(inList.Parameters[1]);
      value := TInteger(inList.Parameters[2]);
      level := Scene.getLevel(name.String_, value.Integer_);
//      level := Scene.Levels[0];
      if level <> nil then begin
        if value.Integer_ = PHYS_LAYER then
          level.SavePhysToXML(aPath + '\phys_layers\' + path.String_ + '.xml')
        else
          level.SaveLogToXML(aPath + '\log_layers\' + path.String_ + '.xml');
//        Scene.Levels.Delete(scene.getLevelIndex(name.String_, value.Integer_));
       end
      else
        raise ESceneManager.Create('No layer to save');
    end;

    PO_SCENE_UNLOAD_PHYS_LAYER : begin
      if Scene.Levels.Count > 0 then
       begin
        Scene.getLevel(0).clearPhysicalLayer;
        aPhysLayer := '';
       end;
    end;

    PO_SCENE_UNLOAD_LOG_LAYER : begin
      if Scene.Levels.Count > 0 then
       begin
        Scene.getLevel(0).clearLogicalLayer;
        Scene.Levels[0].Name := aPhysLayer;
        Scene.getLevel(0).TypeLayer := PHYS_LAYER;
       end;
    end
    ;

    PO_SCENE_UPDATE_LAYER : begin
      path := TString(inlist.Parameters[0]);
      value := TInteger(inList.Parameters[1]);
      newname := TString(inlist.Parameters[2]);
      if inList.Parameters.Count >= 6 then
       begin
        Scene.Levels[0].SectorRowCount := Round(TReal(inList.Parameters[4]).Real_);
        Scene.Levels[0].SectorColumnCount := Round(TReal(inList.Parameters[4]).Real_);
        Scene.Levels[0].SectorSize := TReal(inList.Parameters[3]).Real_ / scene.Levels[0].SectorRowCount;
        Scene.Levels[0].CellSize := Treal(inList.Parameters[5]).Real_;
       end;

      Scene.Levels[0].Name := newname.String_;
      if value.Integer_ = LOG_LAYER then
        scene.Levels[0].SaveLogToXML(aPath +
        '/log_layers/' + path.String_ + '.xml')
      else
        scene.Levels[0].SavePhysToXML(aPath +
        '/phys_layers/' + path.String_ + '.xml')
    end;

    PO_SCENE_LOAD_LOG_LAYER : begin
        outList := TProcessingList.Create;
        outList.addParameter(name);
        outList.addParameter(TInteger.Create(LOG_LAYER));
        item := aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_GET_LAYER_PATH,
          outList));
        scene.Levels[0].LoadLogFromXML(aPath +
        '/log_layers/' + (item.Data as TString).String_ + '.xml');
        scene.Levels[0].TypeLayer := LOG_LAYER;
        if (Scene.Levels[0].Check) then
          Result := TProcessItem.create(PO_SUCCESS, TProcessingLevel.Create(
              scene.Levels[0]))
        else begin
          aMaster.ProcessObject(TProcessItem.create(PO_SCENE_UNLOAD_PHYS_LAYER, nil));
          aMaster.ProcessObject(TProcessItem.create(PO_SCENE_UNLOAD_LOG_LAYER, nil));
          Result := TProcessItem.create(PO_FAILURE, nil);
          raise ESceneManager.Create('Error on load');
        end;
      end;

    PO_SCENE_LOAD_PHYS_LAYER : begin
        Scene.Levels.Clear;
        aPhysLayer := name.String_;
        outList := TProcessingList.Create;
        outList.addParameter(name);
        outList.addParameter(TInteger.Create(PHYS_LAYER));
        item := aMaster.ProcessObject(TProcessItem.create(PO_PROJECT_GET_LAYER_PATH,
          outList));
        TProcessItem.create(PO_SUCCESS, TProcessingLevel.Create(
            Scene.loadLayer(
            aPath + '/phys_layers/' + (item.Data as TString).String_ + '.xml',
            PHYS_LAYER)));
      end;

    PO_SCENE_LOAD :
      begin
        try
          Scene.LoadFromXML(TString(inList.Parameters[0]).String_,
            TProcessingMap(inList.Parameters[1]).Map,
            TProcessingMap(inList.Parameters[2]).Map);
          Result := TProcessItem.create(PO_SUCCESS, nil);
        except on e : Exception do raise ESceneManager.Create('Error on load scene');
          on e1 : ESceneManager do Result := TProcessItem.create(PO_FAILURE, NIL);
        end;
      end;

    PO_SCENE_DELETE_LAYER : begin
        Scene.deleteLevel(TString(inList.Parameters[0]).String_);
        value := TInteger(inList.Parameters[2]);
        path := TString(inList.Parameters[1]);
        if value.Integer_ = PHYS_LAYER then
          DeleteFile(apath + '/phys_layers/' + path.String_ + '.xml')
        else
          DeleteFile(apath + '/log_layers/' + path.String_ + '.xml');
        Result := TProcessItem.create(PO_SUCCESS, NIL);
    end;

    PO_SCENE_GET_ENTITY_BY_ID : begin
        e := Scene.getEntityById(value.Integer_);
        log := TLogicalEntity(e);
        if e <> nil then
          Result := TProcessItem.create(PO_SUCCESS, TEntityProcessing.Create(log))
        else
          Result := TProcessItem.create(PO_FAILURE, TEntityProcessing.Create(log))
    end;

    PO_SCENE_GET_ACTUAL_LEVEL : begin
    //    Result := TProcessItem.create(PO_SUCCESS, TProcessingLevel.Create(Scene.getLevel(name.String_)));
        Result := TProcessItem.create(PO_SUCCESS, TProcessingLevel.Create(Scene.levels[0]));
    end;

    PO_SCENE_INSERT_LAYER : begin
        name := Tstring(inList.Parameters[0]);
        value := TInteger(inList.Parameters[1]);
        if value.Integer_ = PHYS_LAYER then
          Scene.Levels.Clear;
        if inList.Parameters.Count = 4 then
          begin
            height := TReal(inList.Parameters[2]);
            width := TReal(inList.Parameters[3]);
            Scene.addLevel(name.String_, value.Integer_, height.Real_, width.Real_);
          end
        else
          Scene.addLevel(name.String_, value.Integer_, oLevel.DEFAULT_HEIGHT,
          oLevel.DEFAULT_WIDTH);

        Result := TProcessItem.create(PO_SUCCESS, nil);
    end;

    PO_TEST : begin
      test;
      Result := TProcessItem.create(PO_SUCCESS, nil);
    end;

    PO_SCENE_SET_ID : begin
      EntityId := value.Integer_;
      Result := TProcessItem.create(PO_SUCCESS, NIL);
    end;

    PO_SCENE_GET_ID : begin
      Result := TProcessItem.create(PO_SUCCESS, TInteger.Create(EntityId));
    end;

    PO_SCENE_GET_LEVEL : begin
      Result := TProcessItem.create(PO_SUCCESS, TProcessingLevel.Create(Scene.Levels[0]));
    end;

    PO_SCENE_DELETE_WAYPOINT : begin
      try
        Scene.deleteEntity(value.Integer_);
        Result := TProcessItem.create(PO_SUCCESS, nil);
      except
        on E : Exception do raise ESceneManager.Create('Error on insert waypoint');
        on es : ESceneManager do Result := TProcessItem.create(PO_FAILURE, nil);
      end;
    end;

    PO_SCENE_SET_PATH : begin
      aPath := name.String_;
    end;

    PO_SCENE_GET_WAYPOINT : begin
        e := Scene.getEntityById(value.Integer_);
        if e <> nil then
          Result := TProcessItem.create(PO_SUCCESS, TEntityProcessing.Create(e))
        else
          Result := TProcessItem.create(PO_FAILURE, TEntityProcessing.Create(e))
    end;

    PO_SCENE_INSERT_WAYPOINT : begin
      try
       value := TInteger(inList.Parameters[1]);
       phys := createPhysicalEntity(value.Integer_, inList.Parameters[0]);

       waypoint := TWaypoint(aScene.getLevel(aLayerIndex).insertLogicalEntity(aEntityId, ET_WAYPOINT_TYPE,
         phys, aLayerIndex));

       if waypoint  <> nil then
          begin
         //   waypoint.Name := TString(inList.Parameters[0]).String_;
            inc(aEntityId);
            Result := TProcessItem.create(PO_SUCCESS, TInteger.Create(aEntityId - 1))
          end
       else
         Result := TProcessItem.create(PO_FAILURE, nil);
      except
        on E : Exception do raise ESceneManager.Create('Error on insert waypoint');
        on es : ESceneManager do Result := TProcessItem.create(PO_FAILURE, nil);
      end;
    end
   else
      raise ESceneManager.Create('Scene Manager: Could not process message');
      Result := TProcessItem.create(PO_FAILURE, nil);
  end;

 paItem.Free;

end;

procedure TSceneManager.test;
begin
{  level := TLevel.Create(20, 20, 20);
  level.test;
  level.Name := 'phys1';
  level.TypeLayer := oLevel.PHYS_LAYER;
  Scene.addLevel(level);

  level := TLevel.Create(20, 20, 20);
  level.test;
  level.Name := 'log1';
  level.TypeLayer := oLevel.LOG_LAYER;
  Scene.addLevel(level);
 }
end;

end.


